<template>
  <div class="file-upload">
    <div class="file-upload-container" @click="triggerUpload" v-bind="$attrs">
      <slot v-if="fileStatus === 'loading'" name="loading">
        <button class="btn btn-primary" disabled>正在上传...</button>
      </slot>
      <slot v-if="fileStatus === 'success'" name="uploaded" :uploadedData="uploadedData">
        <button class="btn btn-primary">上传成功</button>
      </slot>
      <slot v-else name="default">
        <button class="btn btn-primary">点击上传</button>
      </slot>
    </div>
    <input type="file" class="file-input d-none" @change="handleFileChange" ref="fileInput" />
  </div>
</template>

<script lang="ts">
import axios from 'axios';
import { defineComponent, PropType, ref, watch } from 'vue';
export type UploadStatus = 'ready' | 'loading' | 'success' | 'error';
export type checkFunction = (file: File) => boolean;
export default defineComponent({
  props: {
    action: {
      type: String,
      required: true
    },
    resetfileStatus: {
      type: String
    },
    beforeUpload: {
      type: Function as PropType<checkFunction>
    }
  },
  inheritAttrs: false,
  emits: ['fileUploaded', 'fileUploadedError'],
  setup(props, context) {
    const fileInput = ref<null | HTMLInputElement>(null);
    const fileStatus = ref<UploadStatus>('ready');
    const uploadedData = ref(null);
    const triggerUpload = () => {
      if (fileInput.value) {
        console.log(1212);
        fileInput.value.click();
      }
    };
    watch(
      () => props.resetfileStatus,
      newVal => {
        if (newVal === 'ready') {
          fileStatus.value = 'ready';
        }
      },
      { immediate: true, deep: true }
    );
    const handleFileChange = (e: Event) => {
      const currentTarget = e.target as HTMLInputElement;
      if (currentTarget.files) {
        fileStatus.value = 'loading';
        const files = Array.from(currentTarget.files);
        // 上传之前对文件类型及大小做校验
        if (props.beforeUpload) {
          const result = props.beforeUpload(files[0]);
          if (!result) {
            fileStatus.value = 'ready';
            throw new TypeError();
            // return;
          }
        }
        const formData = new FormData();
        formData.append('file', files[0]);
        axios
          .post(props.action, formData, {
            headers: {
              'Content-Type': 'multipart/form-data'
            }
          })
          .then(res => {
            setTimeout(() => {
              fileStatus.value = 'success';
              uploadedData.value = res.data;
              context.emit('fileUploaded', res.data);
            }, 3000);
          })
          .catch(error => {
            fileStatus.value = 'error';
            console.log({ error }, 'error');
            const { response } = error;
            context.emit('fileUploadedError', response.data);
          })
          .finally(() => {
            if (fileInput.value) {
              fileInput.value.value = '';
            }
          });
      }
    };
    return { fileInput, fileStatus, uploadedData, triggerUpload, handleFileChange };
  }
});
</script>

<style lang="less" scoped>
.file-upload-container {
  display: inline-block;
}
</style>
